<?php
/**
 * @author:  Sebastian Grignoli <grignoli@gmail.com>
 */

class DBBase {

  private static $connections = array();
  private $pdo = array();

  protected function __construct($dsn, $user, $pass) {
    // S�lo puede existir una instancia para cada combinaci�n: base de datos + user + pass

    $this->pdo['data'] = array('dsn' => $dsn, 'user' => $user, 'pass' => $pass);
    return $this;
  }

  public static function getInstance($dsn, $user, $pass) {
    $id = md5($user . ':' . $pass . '@' . $dsn);

    if (!empty(self::$connections[$id])) {
      return self::$connections[$id];
    } else {
      $classname = __CLASS__;
      self::$connections[$id] = new $classname($dsn, $user, $pass);
      return self::$connections[$id];
    }
  }

  public static function getNamedInstance($name) {
    $conns = Config::get('conexiones');
    $conn = $conns[$name];
    return self::getInstance($conn['dsn'], $conn['user'], $conn['pass']);
  }

  public function __call($method_name, $args) {
    // Toda llamada a metodo no implementado en esta clase se forwardea al objeto PDO.
    // Si no esta creado el objeto PDO lo creo ahora.

    if (!method_exists($this->pdo(), $method_name))
      throw new Exception("No existe el metodo 'DB::$method_name'");

    return call_user_func_array(array($this->pdo['pdo'], $method_name), $args);
  }

  protected function createPDO() {
      @$this->pdo['pdo'] = new PDO($this->pdo['data']['dsn'], $this->pdo['data']['user'], $this->pdo['data']['pass'], array(
          PDO::ATTR_TIMEOUT => "10"
      ));
  }

  public function throwError() {
    if ($this->errorCode()) 
      throw new Exception(implode(" - ", $this->errorInfo()));
  }

  public function queryOrException($q){
    $args = func_get_args();
    $result = call_user_func_array(array($this->pdo(), 'query'), $args);

    if((int)$this->pdo()->errorCode())
      throw new Exception(implode(" - ",$this->pdo()->errorInfo())." \nQuery:\n".$q);

    return $result;
  }

  public function pdo(){
    if (empty($this->pdo['pdo']))
      $this->createPDO();
    
    return $this->pdo['pdo'];
  }

  public function executeOrException($query, $params = null){
    $statement = $this->prepare($query);
    if(!is_null($params)){
        $statement->execute($params);
    } else {
        $statement->execute();
    }

    $err = $statement->errorInfo();

    if($err[1]) {
      $e = new Exception(implode(" - ", $err) . "  \nQUERY: " . $query . "  \nParameters: " . var_export($params, 1));
      $e->errorInfo = $err;
      throw $e;
      //throw new Exception(implode(" - ", $err) . "  \nQUERY: " . $query . "  \nParameters: " . var_export($params, 1));
    }

    return $statement;

  }

}